package com.example.edu.Service.ipml;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.example.edu.Dto.*;
import com.example.edu.Entity.Article;
import com.example.edu.Entity.Article_Tag;
import com.example.edu.Entity.Picture;
import com.example.edu.Entity.Tag;
import com.example.edu.Mapper.*;
import com.example.edu.Service.ArticleService;
import com.example.edu.Utils.CacheDataBaseUtil;
import com.example.edu.Utils.JwtUtil;
import com.example.edu.Utils.RegexUtils;
import org.springframework.core.io.ResourceLoader;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.example.edu.Utils.Constants.*;

@Service
public class ArticleServiceImpl implements ArticleService {
    @Resource
    CacheDataBaseUtil cacheDataBaseUtil;
    @Resource
    ArticleMapper articleMapper;
    @Resource
    TagMapper tagMapper;
    @Resource
    Article_TagMapper article_tagMapper;
    @Resource
    Article_PictureMapper article_pictureMapper;
    @Resource
    PictureMapper pictureMapper;
    @Resource
    ResourceLoader resourceLoader;

    @Override
    @Transactional
    public Result create(String token, CreateArticleDto createArticleDto) {
        try {
            return create1(token,createArticleDto);
        } catch (Exception e){
            return Result.fail("创建失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Result create1(String token, CreateArticleDto createArticleDto) {
        String telephone = JwtUtil.getUsername(token);
        String title = createArticleDto.getTitle();
        List<String> tags = createArticleDto.getTags();
        String description = createArticleDto.getDescription();
        Article article = new Article(title, StrUtil.reverse(title),description,telephone);
        List<Tag> tagList = new ArrayList<>();
        for(String tag_name : tags)
            tagList.add(new Tag(tag_name));
        try {
            articleMapper.insertArticle(article);
            int article_id = article.getArticle_id();
            tagList = cacheDataBaseUtil.insertAndGetMany(TAG_KEY,tags,tagList,"tag_id",Integer.class,"tag_name",tagList1 -> tagMapper.insertMany(tagList1),TAG_CACHE_TTL, TimeUnit.HOURS);
            article_tagMapper.insert(article_id,tagList,telephone);
            String path = ARTICLE_ADDRESS + "/" + article_id + ".md";
            File file = new File(path);
            file.createNewFile();
            return Result.ok();
        }catch (Exception e){
            System.out.println(e);
            throw new RuntimeException();
        }
    }

    @Override
    @Transactional
    public Result delete(String token, Article articleId) {
        try {
            return delete1(token,articleId);
        }catch (Exception e){
            return Result.fail("删除失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Result delete1(String token, Article articleId) {
        String telephone = JwtUtil.getUsername(token);
        int article_id = articleId.getArticle_id();
        try {
            articleMapper.delete(article_id);
            article_tagMapper.delete(article_id);
            article_pictureMapper.delete(article_id);
            File file = new File(ARTICLE_ADDRESS + "/" + article_id + ".md");
            if (file.exists())
                file.delete();
        } catch (Exception e){
            System.out.println(e);
            throw new RuntimeException();
        }
        return null;
    }

    @Override
    @Transactional
    public Result update(String token, UpdateArticleDto updateArticleDto) {
        try {
            return update1(token,updateArticleDto);
        }catch (Exception e){
            return Result.fail("修改失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Result update1(String token, UpdateArticleDto updateArticleDto) {
        String telephone = JwtUtil.getUsername(token);
        int article_id = updateArticleDto.getId();
        String title = updateArticleDto.getTitle();
        List<String> tags = updateArticleDto.getTags();
        String description = updateArticleDto.getDescription();
        List<Tag> tagList = new ArrayList<>();
        for (String tag_name: tags)
            tagList.add(new Tag(tag_name));
        try{
            articleMapper.update(title,StrUtil.reverse(title),description,article_id);
            article_tagMapper.delete(article_id);
            tagList = cacheDataBaseUtil.insertAndGetMany(TAG_KEY,tags,tagList,"tag_id",Integer.class,"tag_name",tagList1 -> tagMapper.insertMany(tagList1),TAG_CACHE_TTL, TimeUnit.HOURS);
            article_tagMapper.insert(article_id,tagList,telephone);
            return Result.ok();
        } catch (Exception e) {
            System.out.println(e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public Result getList(String token, PageDto pageDto) {
        String telephone = JwtUtil.getUsername(token);
        int start_index = pageDto.getStartIndex();
        int count = pageDto.getCount();
        int total = articleMapper.getArticleNums(telephone);
        if(total == 0)
            return Result.fail("还没有文章");
        List<PersonalArticleListReturnDto> articles = articleMapper.getArticles(telephone,start_index-1,Math.min(count,total-start_index+1));
        if(articles == null)
            return Result.fail("这一页还没有文章哟");
        for(int i = 0;i < articles.size();i++){
            PersonalArticleListReturnDto article = articles.get(i);
            article.setIndex(i);
            article.setTags(article_tagMapper.getTagNames(article.getArticle_id()));
        }
        ListReturnDto r = new ListReturnDto(total,articles);
        return Result.ok(r);
    }

    @Override
    public Result get(Article articleId) {
        int article_id = articleId.getArticle_id();
        String path = ARTICLE_ADDRESS + "/" + article_id + ".md";
        try {
            org.springframework.core.io.Resource resource = resourceLoader.getResource("file:" + path);
            String content = new String(Files.readAllBytes(Paths.get(resource.getFile().getPath())), StandardCharsets.UTF_8);
            List<Picture> pictures = pictureMapper.getArticlePictures(article_id);
            List<String> urls = new ArrayList<>();
            for(Picture picture : pictures)
                urls.add(BASE_URL + PICTURE_ADDRESS + "/" + picture.getPicture_id() + "." + picture.getType());
            GetArticleReturnDto getArticleReturnDto = new GetArticleReturnDto(content,urls);
            addView(article_id);
            return Result.ok(getArticleReturnDto);
        } catch (IOException e){
            System.out.println(e);
            return Result.fail("获取失败");
        }
    }

    @Async
    protected void addView(int article_id){
        articleMapper.addView(article_id);
    }

    @Override
    @Transactional
    public Result save(String token, SaveDto saveDto){
        try {
            return save1(token,saveDto);
        }catch (Exception e){
            return Result.fail("保存失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Result save1(String token, SaveDto saveDto) {
        String telephone = JwtUtil.getUsername(token);
        int article_id = saveDto.getArticle_id();
        String content = saveDto.getContent();
        List<String> picture_urls = saveDto.getPicture_urls();
        List<Integer> ids = new ArrayList<>();
        for (String picture_url : picture_urls)
            ids.add(RegexUtils.getPictureId(picture_url));
        try{
            article_pictureMapper.delete(article_id);
            if(!ids.isEmpty())
                article_pictureMapper.insertMany(article_id,ids,telephone);
            String path = ARTICLE_ADDRESS + "/" + article_id + ".md";
            File file = new File(path);
            BufferedWriter writer = new BufferedWriter(new FileWriter(file, false));
            writer.write(content);
            return Result.ok();
        }catch (Exception e){
            System.out.println(e);
            throw new RuntimeException();
        }
    }

    @Override
    public Result recall(Article articleId) {
        articleMapper.recall(articleId.getArticle_id());
        return Result.ok();
    }

    @Override
    public Result search(String token, UnionSearchDto unionSearchDto) {
        String telephone = JwtUtil.getUsername(token);
        int start = unionSearchDto.getStartIndex();
        int count = unionSearchDto.getCount();
        String put = unionSearchDto.getPut();
        Timestamp begin = unionSearchDto.getBegin();
        Timestamp end = unionSearchDto.getEnd();
        List<Integer> tags = unionSearchDto.getTags();
        List<PersonalArticleListReturnDto> articles = articleMapper.getArticlesByUnion(telephone,put,StrUtil.reverse(put),begin,end);
        List<PersonalArticleListReturnDto> rs = new ArrayList<>();
        if(articles.isEmpty())
            return Result.fail("没有搜索到文章");
        if(tags.isEmpty()){
            int size = articles.size();
            if(start >= size)
                return Result.fail("这一页还没有文章");
            rs = articles.subList(start,Math.min(start+count+1,size));
            for(int i = 0;i < rs.size();i++){
                PersonalArticleListReturnDto r = rs.get(i);
                r.setIndex(i);
                r.setTags(article_tagMapper.getTagNames(r.getArticle_id()));
            }
            return Result.ok(new ListReturnDto(size,rs));
        }
        List<Integer> article_ids = new ArrayList<>();
        for (PersonalArticleListReturnDto article : articles)
            article_ids.add(article.getArticle_id());
        List<Article_Tag> relations = article_tagMapper.getRelations(article_ids);
        int i = 0;
        for (PersonalArticleListReturnDto article : articles){
            List<Integer> tag_ids = new ArrayList<>();
            for(;i < relations.size();i++){
                if (article.getArticle_id() != relations.get(i).getArticle_id())
                    break;
                tag_ids.add(relations.get(i).getTag_id());
            }
            if(tag_ids.containsAll(tags)) {
                article.setTag_ids(tag_ids);
                rs.add(article);
            }
        }
        if(rs.isEmpty())
            return Result.fail("没有搜索到文章");
        int size = rs.size();
        if(start >= size)
            return Result.fail("这一页还没有文章");
        rs = rs.subList(start,Math.min(start+count+1,size));
        for(int j = 0;j < rs.size();j++){
            PersonalArticleListReturnDto r = rs.get(j);
            r.setIndex(j);
            r.setTags(tagMapper.getTagNames(r.getTag_ids()));
        }
        return Result.ok(new ListReturnDto(size,rs));
    }

    @Override
    public Result getTags(String token) {
        String telephone = JwtUtil.getUsername(token);
        return Result.ok(tagMapper.getTags(telephone));
    }
}
